home *** CD-ROM | disk | FTP | other *** search
/ Aminet 51 / Aminet 51 (2002)(GTI - Schatztruhe)[!][Oct 2002].iso / Aminet / util / misc / ReportPlus.lha / reportplus / source / f8.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-23  |  72.1 KB  |  2,029 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <proto/exec.h>
  4. #include <intuition/intuition.h>
  5. #include <intuition/gadgetclass.h>
  6. #include <proto/intuition.h>
  7. #include <libraries/gadtools.h>
  8. #include <proto/gadtools.h>
  9. #include <dos/dos.h>
  10. #include <dos/exall.h>
  11. #include <dos/dostags.h>
  12. #include <proto/dos.h>
  13. #include <graphics/gfx.h>
  14. #include <clib/graphics_protos.h>
  15. #include <clib/alib_protos.h>
  16. #include <libraries/asl.h>
  17. #include <clib/asl_protos.h>
  18.  
  19. #include <ctype.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "rp.h"
  23.  
  24. #define ALL_REACTION_CLASSES
  25. #include <reaction/reaction.h>
  26.  
  27. #define LIMIT_DIRS        8196
  28. #define MAX_FILES (128 * 1024)
  29. #define TRUNCATE            39
  30. #define GRANULARITY_DIRS    10
  31. #define GRANULARITY_FILES   10
  32.  
  33. /* Limitations:
  34.    LIMIT_DIRS (top-level list entries).
  35.    MAX_FILES (total files/dirs in path). */
  36.  
  37. MODULE void pop(void);
  38. MODULE void push(STRPTR name, ULONG theindex);
  39. MODULE void subdir(ULONG theindex);
  40. MODULE void parent(void);
  41. MODULE void root(void);
  42. MODULE void pathasl(void);
  43. MODULE void showduplicates(void);
  44. MODULE void addduplicate(STRPTR path, STRPTR filename);
  45. MODULE void writeline(void);
  46. MODULE void killduplist(void);
  47. MODULE void killsizelist(void);
  48. MODULE void ghost(void);
  49. MODULE void unghost(void);
  50. MODULE void scale(ULONG bytes);
  51. MODULE void __inline progressbar(ULONG level);
  52.  
  53. #define UNITOPTIONS 3 // counting from 0
  54. MODULE STRPTR UnitOptions[UNITOPTIONS + 1] =
  55. {   "Bytes",
  56.     "Kilobytes",
  57.     "Megabytes",
  58.     "Blocks"
  59. };
  60.  
  61. MODULE struct ColumnInfo SizeColumnInfo[] =
  62. { { 75,            // WORD   ci_Width
  63.     "Pathname",    // STRPTR ci_Title
  64.     0,             // ULONG  ci_Flags
  65.   },
  66.   { 25,
  67.     "Size",
  68.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  69.           to the right border of the relevant column). */
  70.   },
  71.   { -1, (STRPTR) ~0, -1
  72. } },
  73. DupColumnInfo[] =
  74. { { 40,            // WORD   ci_Width
  75.     "Pathname",    // STRPTR ci_Title
  76.     0,             // ULONG  ci_Flags
  77.   },
  78.   { 10,
  79.     "Byte size",
  80.     0,
  81.   },
  82.   { 10,
  83.     "Date",
  84.     0,
  85.   },
  86.   { 10,
  87.     "Time",
  88.     0,
  89.   },
  90.   { 30,
  91.     "Version",
  92.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  93.           to the right border of the relevant column). */
  94.   },
  95.   { -1, (STRPTR) ~0, -1
  96. } };
  97.  
  98. IMPORT struct TextAttr     Topaz8;
  99. IMPORT SBYTE               page;
  100. IMPORT TEXT                globalname[PATHNAMEFIELD + 1],
  101.                            weekdaystring[10],
  102.                            datestring[10],
  103.                            timestring[9],
  104.                            asldir[PATHNAMEFIELD + 1],
  105.                            aslresult[PATHNAMEFIELD + 1],
  106.                            IOBuffer[LONGESTFIELD + 1];
  107. IMPORT struct SharedStruct shared;
  108. IMPORT struct Screen*      ScreenPtr;
  109. IMPORT struct Window*      MainWindowPtr;
  110. IMPORT struct ExAllData*   EADataPtr;
  111. IMPORT struct Menu*        MenuPtr;
  112. IMPORT Object*             WinObject[FUNCTIONS + 1];
  113. IMPORT ULONG               increment;
  114.  
  115. AGLOBAL struct Gadget*     size_gadgets[GIDS_8 + 1];
  116.  
  117. MODULE ABOOL               DupNodes       = FALSE,
  118.                            SizeNodes      = FALSE,
  119.                            EmptyDupNodes  = FALSE,
  120.                            EmptySizeNodes = FALSE,
  121.                            ram            = FALSE;
  122. MODULE struct List         SizeList,
  123.                            DupList,
  124.                            EmptySizeList,
  125.                            EmptyDupList;
  126. MODULE STRPTR*             PathnamePtr;
  127. MODULE STRPTR*             FilenamePtr;
  128. MODULE STRPTR*             StackPtr;
  129. MODULE STRPTR*             DirNamePtr;
  130. MODULE ABOOL*              IsDup;
  131. MODULE BPTR                TempHandle     = NULL,
  132.                            DirHandle      = NULL,
  133.                            LogFileHandle  = NULL;
  134. MODULE TEXT                logstring[PATHNAMEFIELD + 1],
  135.                            liststring[5][PATHNAMEFIELD + 1];
  136. MODULE UBYTE               commastring[13 + 1],
  137.                            pathlength;
  138. MODULE ULONG               DirNamesAllocated  = 0,
  139.                            FileNamesAllocated = 0,
  140.                            files              = 0, // how many files have been found. Counting from 1.
  141.                            status             = STATUS_READY;
  142.  
  143. MODULE struct
  144. {   ULONG entries, total, free, capacity, stackentries,
  145.           blocksize, view, numfiles, numdirs,
  146.           log, finddup, slack; // really booleans
  147.     TEXT  oldpath[PATHNAMEFIELD + 1], path[PATHNAMEFIELD + 1], logfile[PATHNAMEFIELD + 1];
  148.     LONG  type[LIMIT_DIRS];
  149.     ULONG bytes[LIMIT_DIRS], topdir[LIMIT_DIRS];
  150. } size =
  151. {   0, 0, 0, 0, 0,
  152.     0, 0, 0, 0,
  153.     (ULONG) TRUE, (ULONG) FALSE, (ULONG) FALSE,
  154.     "RAM:", "RAM:", "RAM:ReportPlus.txt"
  155. };
  156.  
  157. AGLOBAL void size_init(void)
  158. {   struct Node* ListBrowserNodePtr;
  159.  
  160.     NewList(&SizeList);
  161.     NewList(&DupList);
  162.  
  163.     /* Create a 2-column listbrowser list with only one node containing
  164.     only column tags. */
  165.     NewList(&EmptySizeList);
  166.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  167.     (   2,                  // columns
  168.         /* LBNCA_ tags are those that apply to the specific column. */
  169.         LBNA_Column,        0,
  170.         LBNA_Column,        1,
  171.         TAG_END
  172.     )))
  173.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  174.     }
  175.     AddTail(&EmptySizeList, ListBrowserNodePtr); // AddTail() has no return code
  176.     EmptySizeNodes = TRUE;
  177.  
  178.     /* Create a 5-column listbrowser list with only one node containing
  179.     only column tags. */
  180.     NewList(&EmptyDupList);
  181.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  182.     (   5,                  // columns
  183.         /* LBNCA_ tags are those that apply to the specific column. */
  184.         LBNA_Column,        0,
  185.         LBNA_Column,        1,
  186.         LBNA_Column,        2,
  187.         LBNA_Column,        3,
  188.         LBNA_Column,        4,
  189.         TAG_END
  190.     )))
  191.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  192.     }
  193.     AddTail(&EmptyDupList, ListBrowserNodePtr); // AddTail() has no return code
  194.     EmptyDupNodes = TRUE;
  195. }
  196.  
  197. AGLOBAL void size1(void)
  198. {   struct Hook         Hook8Struct;
  199.     struct List         ChooserList;
  200.     struct ChooserNode* ChooserNodePtr[UNITOPTIONS + 1];
  201.     ULONG               i;
  202.  
  203.     NewList(&ChooserList);
  204.     for (i = 0; i <= UNITOPTIONS; i++)
  205.     {   if (!(ChooserNodePtr[i] = (struct ChooserNode *) AllocChooserNode(CNA_Text, UnitOptions[i], TAG_DONE)))
  206.         {   rq("Can't allocate chooser node!");
  207.         }
  208.         AddTail(&ChooserList, (struct Node *) ChooserNodePtr[i]);
  209.     } // automatically freed by ReAction at DisposeObject() time
  210.  
  211.     InitHook(&Hook8Struct, Hook8Func, NULL);
  212.  
  213.     /* Create the window object. */
  214.     lockscreen();
  215.  
  216.     /* We can't just use EmptyList for an empty columnar list, we
  217.     actually need a node (with the LBNA_Column tags) to be present.
  218.  
  219.     LISTBROWSER_ScrollRaster seems not to be usable with
  220.     multi-column lists. */
  221.  
  222.     if (!(WinObject[8] =          NewObject(WINDOW_GetClass(), NULL,
  223.     // window
  224.     WA_PubScreen,                 ScreenPtr,
  225.     WA_ScreenTitle,               "Report+",
  226.     WA_Title,                     "Report+: Path Size Report",
  227.     WA_Activate,                  TRUE,
  228.     WA_DepthGadget,               TRUE,
  229.     WA_DragBar,                   TRUE,
  230.     WA_CloseGadget,               TRUE,
  231.     WA_SizeGadget,                TRUE,
  232.     WA_IDCMP,                     IDCMP_RAWKEY,
  233.     WINDOW_IDCMPHook,             &Hook8Struct,
  234.     WINDOW_IDCMPHookBits,         IDCMP_RAWKEY,
  235.     WINDOW_MenuStrip,             MenuPtr,
  236.     WINDOW_Position,              WPOS_CENTERSCREEN,
  237.     WINDOW_ParentGroup,           size_gadgets[GID_8_LY1] =
  238.     NewObject
  239.     (       LAYOUT_GetClass(), NULL,
  240.             // root-layout
  241.             LAYOUT_Orientation,        LAYOUT_ORIENT_VERT,
  242.             LAYOUT_SpaceOuter,         TRUE,
  243.             LAYOUT_DeferLayout,        TRUE,
  244.             LAYOUT_AddChild,
  245.             NewObject
  246.             (   LAYOUT_GetClass(),     NULL,
  247.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  248.                 LAYOUT_SpaceOuter,     TRUE,
  249.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  250.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  251.                 LAYOUT_BevelStyle,     BVS_NONE,
  252.                 LAYOUT_AddImage,
  253.                 NewObject
  254.                 (   LABEL_GetClass(),  NULL,
  255.                     LABEL_Text,        "_Path:",
  256.                     LABEL_Justification,LJ_LEFT,
  257.                 TAG_END),
  258.                 CHILD_WeightedWidth,   0,
  259.                 LAYOUT_AddChild,       size_gadgets[GID_8_ST1] =
  260.                 NewObject
  261.                 (   STRING_GetClass(), NULL,
  262.                     GA_ID,             GID_8_ST1,
  263.                     GA_RelVerify,      TRUE,
  264.                     STRINGA_TextVal,   size.path,
  265.                     STRINGA_MinVisible,20,
  266.                 TAG_END),
  267.                 LAYOUT_AddChild,       size_gadgets[GID_8_BU1] =
  268.                 NewObject(NULL,        "button.gadget",
  269.                     GA_ID,             GID_8_BU1,
  270.                     GA_RelVerify,      TRUE,
  271.                     BUTTON_AutoButton, BAG_POPFILE,
  272.                 TAG_END),
  273.                 CHILD_WeightedWidth,   0,
  274.             TAG_END),
  275.             CHILD_WeightedHeight,      0,
  276.             LAYOUT_AddChild,           NewObject(LAYOUT_GetClass(), NULL,
  277.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  278.                 LAYOUT_SpaceOuter,     TRUE,
  279.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  280.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  281.                 LAYOUT_BevelStyle,     BVS_NONE,
  282.                 LAYOUT_ShrinkWrap,     TRUE,
  283.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB1] =
  284.                 NewObject
  285.                 (   CHECKBOX_GetClass(),NULL,
  286.                     // checkbox
  287.                     GA_ID,             GID_8_CB1,
  288.                     GA_RelVerify,      TRUE,
  289.                     GA_Text,           "_Log to:",
  290.                     GA_Selected,       (BOOL) size.log,
  291.                     TAG_END
  292.                 ),
  293.                 CHILD_WeightedWidth,   0,
  294.                 LAYOUT_AddChild,       size_gadgets[GID_8_ST2] =
  295.                                        NewObject(STRING_GetClass(), NULL,
  296.                     // string        
  297.                     GA_ID,             GID_8_ST2,
  298.                     GA_RelVerify,      TRUE,
  299.                     STRINGA_TextVal,   size.logfile,
  300.                     STRINGA_MinVisible,20,
  301.                     GA_Disabled,       !size.log,
  302.                     TAG_END
  303.                 ),
  304.                 LAYOUT_AddChild,       size_gadgets[GID_8_BU3] =
  305.                 NewObject
  306.                 (   NULL,              "button.gadget",
  307.                     // button
  308.                     GA_ID,             GID_8_BU3,
  309.                     GA_RelVerify,      TRUE,
  310.                     BUTTON_AutoButton, BAG_POPFILE,
  311.                     GA_Disabled,       !size.log,
  312.                     TAG_END
  313.                 ),
  314.                 CHILD_WeightedWidth,   0,
  315.                 TAG_END
  316.             ),
  317.             CHILD_WeightedHeight,      0,
  318.             LAYOUT_AddChild,
  319.             NewObject
  320.             (   LAYOUT_GetClass(),     NULL,
  321.                 LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  322.                 LAYOUT_SpaceOuter,     TRUE,
  323.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  324.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  325.                 LAYOUT_BevelStyle,     BVS_FIELD,
  326.                 LAYOUT_AddChild,
  327.                 NewObject
  328.                 (   LAYOUT_GetClass(),     NULL,
  329.                     LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  330.                     LAYOUT_SpaceOuter,     TRUE,
  331.                     LAYOUT_VertAlignment,  LALIGN_CENTER,
  332.                     LAYOUT_HorizAlignment, LALIGN_CENTER,
  333.                     LAYOUT_BevelStyle,     BVS_NONE,
  334.                     LAYOUT_AddChild,       size_gadgets[GID_8_BU6] =
  335.                     NewObject
  336.                     (   NULL,              "button.gadget",
  337.                         GA_ID,             GID_8_BU6,
  338.                         GA_RelVerify,      TRUE,
  339.                         GA_Text,           "_Root",
  340.                         TAG_END
  341.                     ),
  342.                     CHILD_WeightedWidth,   50,
  343.                     LAYOUT_AddChild,       size_gadgets[GID_8_BU7] =
  344.                     NewObject             
  345.                     (   NULL,              "button.gadget",
  346.                         GA_ID,             GID_8_BU7,
  347.                         GA_RelVerify,      TRUE,
  348.                         GA_Text,           "P_arent",
  349.                         TAG_END
  350.                     ),
  351.                     CHILD_WeightedWidth,   50,
  352.                 TAG_END),
  353.                 CHILD_WeightedHeight,      0,
  354.                 LAYOUT_AddChild,           size_gadgets[GID_8_LB2] =
  355.                 NewObject
  356.                 (   LISTBROWSER_GetClass(),NULL,
  357.                     GA_ID,                 GID_8_LB2,
  358.                     GA_RelVerify,          TRUE,
  359.                     GA_TextAttr,           &Topaz8,
  360.                     LISTBROWSER_Labels,    (ULONG) &EmptySizeList,
  361.                     LISTBROWSER_ColumnInfo,(ULONG) &SizeColumnInfo,
  362.                     LISTBROWSER_ColumnTitles,TRUE,
  363.                     LISTBROWSER_MinVisible,6,
  364.                 TAG_END),
  365.                 CHILD_WeightedHeight,      100,
  366.                 CHILD_MinHeight,           80,
  367.                 LAYOUT_AddChild,
  368.                 NewObject
  369.                 (   LAYOUT_GetClass(),     NULL,
  370.                     LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  371.                     LAYOUT_SpaceOuter,     TRUE,
  372.                     LAYOUT_VertAlignment,  LALIGN_LEFT,
  373.                     LAYOUT_HorizAlignment, LALIGN_RIGHT,
  374.                     LAYOUT_BevelStyle,     BVS_NONE,
  375.                     LAYOUT_AddChild,
  376.                     NewObject
  377.                     (   LAYOUT_GetClass(),     NULL,
  378.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  379.                         LAYOUT_SpaceOuter,     TRUE,
  380.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  381.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  382.                         LAYOUT_BevelStyle,     BVS_NONE,
  383.                         LAYOUT_AddImage,
  384.                         NewObject
  385.                         (   LABEL_GetClass(),  NULL,
  386.                             LABEL_Text,        "Files:",
  387.                             LABEL_Justification,LJ_CENTRE,
  388.                         TAG_END),
  389.                         CHILD_WeightedHeight,  0,
  390.                         LAYOUT_AddImage,
  391.                         NewObject
  392.                         (   LABEL_GetClass(),  NULL,
  393.                             LABEL_Text,        "Directories:",
  394.                             LABEL_Justification,LJ_CENTRE,
  395.                         TAG_END),
  396.                         CHILD_WeightedHeight,  0,
  397.                         LAYOUT_AddImage,
  398.                         NewObject
  399.                         (   LABEL_GetClass(),  NULL,
  400.                             LABEL_Text,        "Block size:",
  401.                             LABEL_Justification,LJ_CENTRE,
  402.                         TAG_END),
  403.                         CHILD_WeightedHeight,  0,
  404.                     TAG_END),
  405.                     CHILD_WeightedWidth,       0,
  406.                     LAYOUT_AddChild,
  407.                     NewObject
  408.                     (   LAYOUT_GetClass(),     NULL,
  409.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  410.                         LAYOUT_SpaceOuter,     TRUE,
  411.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  412.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  413.                         LAYOUT_BevelStyle,     BVS_NONE,
  414.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST6] =
  415.                         NewObject
  416.                         (   STRING_GetClass(), NULL,
  417.                             GA_ID,             GID_8_ST6,
  418.                             GA_ReadOnly,       TRUE,
  419.                             STRINGA_TextVal,   "-",
  420.                             STRINGA_MinVisible,13,
  421.                             STRINGA_Justification,GACT_STRINGRIGHT,
  422.                             GA_TextAttr,       &Topaz8,
  423.                         TAG_END),
  424.                         CHILD_WeightedHeight,  0,
  425.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST7] =
  426.                         NewObject
  427.                         (   STRING_GetClass(), NULL,
  428.                             GA_ID,             GID_8_ST7,
  429.                             GA_ReadOnly,       TRUE,
  430.                             STRINGA_TextVal,   "-",
  431.                             STRINGA_MinVisible,13,
  432.                             STRINGA_Justification,GACT_STRINGRIGHT,
  433.                             GA_TextAttr,       &Topaz8,
  434.                         TAG_END),
  435.                         CHILD_WeightedHeight,  0,
  436.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST8] =
  437.                         NewObject
  438.                         (   STRING_GetClass(), NULL,
  439.                             GA_ID,             GID_8_ST8,
  440.                             GA_ReadOnly,       TRUE,
  441.                             STRINGA_TextVal,   "-",
  442.                             STRINGA_MinVisible,13,
  443.                             STRINGA_Justification,GACT_STRINGRIGHT,
  444.                             GA_TextAttr,       &Topaz8,
  445.                         TAG_END),
  446.                         CHILD_WeightedHeight,  0,
  447.                     TAG_END),
  448.                     CHILD_WeightedWidth,       0,
  449.                     LAYOUT_AddImage,           NewObject
  450.                     (   LABEL_GetClass(),      NULL,
  451.                         LABEL_Text,            "",
  452.                         TAG_END
  453.                     ),
  454.                     CHILD_WeightedWidth,       100,
  455.                     LAYOUT_AddChild,
  456.                     NewObject
  457.                     (   LAYOUT_GetClass(),     NULL,
  458.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  459.                         LAYOUT_SpaceOuter,     TRUE,
  460.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  461.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  462.                         LAYOUT_BevelStyle,     BVS_NONE,
  463.                         LAYOUT_AddImage,
  464.                         NewObject
  465.                         (   LABEL_GetClass(),  NULL,
  466.                             LABEL_Text,        "Used in path:",
  467.                             LABEL_Justification,LJ_RIGHT,
  468.                         TAG_END),
  469.                         CHILD_WeightedHeight,  0,
  470.                         LAYOUT_AddImage,
  471.                         NewObject
  472.                         (   LABEL_GetClass(),  NULL,
  473.                             LABEL_Text,        "Free on volume:",
  474.                             LABEL_Justification,LJ_RIGHT,
  475.                         TAG_END),
  476.                         CHILD_WeightedHeight,  0,
  477.                         LAYOUT_AddImage,
  478.                         NewObject
  479.                         (   LABEL_GetClass(),  NULL,
  480.                             LABEL_Text,        "Volume capacity:",
  481.                             LABEL_Justification,LJ_RIGHT,
  482.                         TAG_END),
  483.                         CHILD_WeightedHeight,  0,
  484.                     TAG_END),
  485.                     CHILD_WeightedWidth,       0,
  486.                     LAYOUT_AddChild,
  487.                     NewObject
  488.                     (   LAYOUT_GetClass(),     NULL,
  489.                         LAYOUT_Orientation,    LAYOUT_ORIENT_VERT,
  490.                         LAYOUT_SpaceOuter,     TRUE,
  491.                         LAYOUT_VertAlignment,  LALIGN_CENTER,
  492.                         LAYOUT_HorizAlignment, LALIGN_RIGHT,
  493.                         LAYOUT_BevelStyle,     BVS_NONE,
  494.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST4] =
  495.                         NewObject
  496.                         (   STRING_GetClass(), NULL,
  497.                             GA_ID,             GID_8_ST4,
  498.                             GA_ReadOnly,       TRUE,
  499.                             STRINGA_TextVal,   "-",
  500.                             STRINGA_MinVisible,13,
  501.                             STRINGA_Justification,GACT_STRINGRIGHT,
  502.                             GA_TextAttr,       &Topaz8,
  503.                         TAG_END),
  504.                         CHILD_WeightedHeight,  0,
  505.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST5] =
  506.                         NewObject
  507.                         (   STRING_GetClass(), NULL,
  508.                             GA_ID,             GID_8_ST5,
  509.                             GA_ReadOnly,       TRUE,
  510.                             STRINGA_TextVal,   "-",
  511.                             STRINGA_MinVisible,13,
  512.                             STRINGA_Justification,GACT_STRINGRIGHT,
  513.                             GA_TextAttr,       &Topaz8,
  514.                         TAG_END),
  515.                         CHILD_WeightedHeight,  0,
  516.                         LAYOUT_AddChild,       size_gadgets[GID_8_ST3] =
  517.                         NewObject
  518.                         (   STRING_GetClass(), NULL,
  519.                             GA_ID,             GID_8_ST3,
  520.                             GA_ReadOnly,       TRUE,
  521.                             STRINGA_TextVal,   "-",
  522.                             STRINGA_MinVisible,13,
  523.                             STRINGA_Justification,GACT_STRINGRIGHT,
  524.                             GA_TextAttr,       &Topaz8,
  525.                         TAG_END),
  526.                         CHILD_WeightedHeight,  0,
  527.                     TAG_END),
  528.                     CHILD_WeightedWidth,       0,
  529.                 TAG_END),
  530.                 CHILD_WeightedHeight,          0,
  531.             TAG_END),
  532.             CHILD_WeightedHeight,              70,
  533.             LAYOUT_AddChild,
  534.             NewObject
  535.             (   LAYOUT_GetClass(),     NULL,
  536.                 LAYOUT_Orientation,    LAYOUT_ORIENT_HORIZ,
  537.                 LAYOUT_SpaceOuter,     TRUE,
  538.                 LAYOUT_VertAlignment,  LALIGN_CENTER,
  539.                 LAYOUT_HorizAlignment, LALIGN_CENTER,
  540.                 LAYOUT_BevelStyle,     BVS_NONE,
  541.                 LAYOUT_AddImage,
  542.                 NewObject
  543.                 (   LABEL_GetClass(),  NULL,
  544.                     // label
  545.                     LABEL_Text,        "_View as:",
  546.                     LABEL_Justification,LJ_RIGHT,
  547.                 TAG_END),
  548.                 CHILD_WeightedWidth,   0,
  549.                 LAYOUT_AddChild,       size_gadgets[GID_8_CH1] =
  550.                 NewObject
  551.                 (   CHOOSER_GetClass(),NULL,
  552.                     GA_ID,             GID_8_CH1,
  553.                     GA_RelVerify,      TRUE,
  554.                     CHOOSER_PopUp,     TRUE,
  555.                     CHOOSER_Labels,    &ChooserList,
  556.                     CHOOSER_Selected,  size.view,
  557.                     TAG_END
  558.                 ),
  559.                 CHILD_WeightedWidth,   0,
  560.                 LAYOUT_AddImage,       NewObject
  561.                 (   LABEL_GetClass(),  NULL,
  562.                     LABEL_Text,        "",
  563.                     TAG_END
  564.                 ),
  565.                 CHILD_WeightedWidth,   100,
  566.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB2] =
  567.                 NewObject
  568.                 (   CHECKBOX_GetClass(),NULL,
  569.                     // checkbox
  570.                     GA_ID,             GID_8_CB2,
  571.                     GA_RelVerify,      TRUE,
  572.                     GA_Text,           "Include _slack?",
  573.                     GA_Selected,       (BOOL) size.slack,
  574.                 TAG_END),
  575.                 CHILD_WeightedWidth,   0,
  576.                 LAYOUT_AddChild,       size_gadgets[GID_8_CB3] =
  577.                 NewObject
  578.                 (   CHECKBOX_GetClass(),NULL,
  579.                     // checkbox
  580.                     GA_ID,             GID_8_CB3,
  581.                     GA_RelVerify,      TRUE,
  582.                     GA_Text,           "Find _duplicates?",
  583.                     GA_Selected,       (BOOL) size.finddup,
  584.                     TAG_END
  585.                 ),
  586.                 CHILD_WeightedWidth,   0,
  587.             TAG_END),
  588.             CHILD_WeightedHeight,     0,
  589.             LAYOUT_AddChild,          size_gadgets[GID_8_LB1] =
  590.             NewObject
  591.             (   LISTBROWSER_GetClass(),NULL,
  592.                 GA_ID,                GID_8_LB1,
  593.                 GA_ReadOnly,          TRUE,
  594.                 GA_TextAttr,          &Topaz8,
  595.                 GA_Disabled,          !size.finddup,
  596.                 LISTBROWSER_Labels,   (ULONG) &EmptyDupList,
  597.                 LISTBROWSER_ColumnInfo,(ULONG) &DupColumnInfo,
  598.                 LISTBROWSER_ColumnTitles,TRUE,
  599.                 LISTBROWSER_HorizontalProp,TRUE,
  600.                 LISTBROWSER_VirtualWidth,620 + 155,
  601.                 LISTBROWSER_MinVisible,6,
  602.             TAG_END),
  603.             CHILD_WeightedHeight,     30,
  604.             CHILD_MinHeight,          80,
  605.             LAYOUT_AddChild,          size_gadgets[GID_8_FG1] =
  606.             NewObject
  607.             (   FUELGAUGE_GetClass(), NULL,
  608.                 GA_ID,                GID_8_FG1,
  609.                 GA_Text,              "Ready.",
  610.                 FUELGAUGE_Level,      0,
  611.                 FUELGAUGE_Percent,    FALSE,
  612.                 FUELGAUGE_Justification,FGJ_CENTER,
  613.             TAG_END),
  614.             CHILD_WeightedHeight,     0,
  615.             LAYOUT_AddChild,
  616.             NewObject
  617.             (   LAYOUT_GetClass(),    NULL,
  618.                 LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  619.                 LAYOUT_SpaceOuter,    TRUE,
  620.                 LAYOUT_VertAlignment, LALIGN_CENTER,
  621.                 LAYOUT_HorizAlignment,LALIGN_CENTER,
  622.                 LAYOUT_BevelStyle,    BVS_NONE,
  623.                 LAYOUT_AddChild,      size_gadgets[GID_8_BU4] =
  624.                 NewObject
  625.                 (   NULL,             "button.gadget",
  626.                     GA_ID,            GID_8_BU4,
  627.                     GA_RelVerify,     TRUE,
  628.                     GA_Text,          "_Update",
  629.                 TAG_END),
  630.                 LAYOUT_AddChild,      size_gadgets[GID_8_BU5] =
  631.                 NewObject
  632.                 (   NULL,             "button.gadget",
  633.                     GA_ID,            GID_8_BU5,
  634.                     GA_RelVerify,     TRUE,
  635.                     GA_Text,          "Stop",
  636.                     GA_Disabled,      TRUE,
  637.                 TAG_END),
  638.             TAG_END),
  639.             CHILD_WeightedHeight,     0,
  640.     TAG_END)
  641.     )))
  642.     {   rq("Can't create ReAction objects!");
  643.     }
  644.     unlockscreen();
  645.     openwindow();
  646.     ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST1]);
  647.  
  648.     loop();
  649.     closewindow();
  650.     size_exit();
  651. }
  652.  
  653. AGLOBAL void updatesize(void)
  654. {   BOOL                  more; // note that it is BOOL, not ABOOL
  655.     TEXT                  tempstring[PATHNAMEFIELD + 1],
  656.                           tempname[LONGFIELD + 1];
  657.     ULONG                 i, j, tempbytes, where;
  658.     LONG                  length, temptype; // these both MUST be signed
  659.     ABOOL                 failed      = FALSE;
  660.     struct FileInfoBlock* FIBPtr      = NULL;
  661.     struct InfoData*      InfoDataPtr;
  662.     struct ExAllControl*  eac;
  663.     struct ExAllData*     ead;
  664.     struct Node*          ListBrowserNodePtr;
  665.  
  666. /* 0: Ready
  667.    1: Reading directory...
  668.  ! 2: Reading subdirectories...
  669.    3: Sorting contents...
  670.  ![4: Matching duplicates...
  671.   [5: Condensing duplicates...
  672.   [6: Sorting duplicates...
  673.  ![7: Examining duplicates...
  674.  
  675. [ = only for duplicates
  676. ! = can be aborted by user
  677.  */
  678.  
  679.     if (SizeNodes)
  680.     {   clearlist(&SizeList);
  681.         SizeNodes = FALSE;
  682.     }
  683.     if (!DirNamePtr)
  684.     {   if (!(DirNamePtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  685.         {   rq("Out of memory!");
  686.     }   }
  687.  
  688.     // 1: Ghost relevant gadgets, for duration of the operation.
  689.  
  690.     ghost();
  691.     SetGadgetAttrs
  692.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  693.         FUELGAUGE_Min,   0,
  694.         FUELGAUGE_Max,   100,
  695.         FUELGAUGE_Level, 25,
  696.         GA_Text,         "Reading directory...",
  697.         TAG_END
  698.     ); // we don't know how many files in advance...
  699.  
  700.     // 2: Now get a Lock() on the path.
  701.  
  702.     size.stackentries = size.entries = size.numdirs = size.numfiles = 0;
  703.     /* From RKRM I&A, p. 65: */
  704.     if
  705.     (   !(DirHandle = (BPTR) Lock(size.path, ACCESS_READ))
  706.      || !(FIBPtr    = AllocDosObject(DOS_FIB, NULL))
  707.      || !(            Examine(DirHandle, FIBPtr))
  708.      ||  (FIBPtr->fib_DirEntryType <= 0) // if not a directory
  709.     )
  710.     {   failed = TRUE;
  711.     }
  712.  
  713.     strcpy(size.oldpath, size.path);
  714.     if (FIBPtr)
  715.     {   FreeDosObject(DOS_FIB, FIBPtr);
  716.         // FIBPtr = NULL;
  717.     }
  718.     if (failed)
  719.     {   DisplayBeep(ScreenPtr);
  720.         unghost();
  721.  
  722.         strcpy(size.path, size.oldpath);
  723.         SetGadgetAttrs
  724.         (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  725.             STRINGA_TextVal, size.path,
  726.             TAG_END
  727.         );
  728.         SetGadgetAttrs
  729.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  730.             FUELGAUGE_Level, 0,
  731.             GA_Text,         "Failed!",
  732.             TAG_END
  733.         );
  734.         return;
  735.     }
  736.     SetGadgetAttrs
  737.     (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  738.         STRINGA_TextVal, size.path,
  739.         TAG_END
  740.     );
  741.  
  742.     /* 3: Now we call Info() to ascertain the free bytes.
  743.           InfoDataPtr must be longword-aligned. */
  744.  
  745.     if (!(InfoDataPtr = AllocVec(sizeof(struct InfoData), MEMF_CLEAR)))
  746.     {   rq("Out of memory!");
  747.     }
  748.     if (Info(DirHandle, InfoDataPtr))
  749.     {   size.blocksize = InfoDataPtr->id_BytesPerBlock;
  750.         size.free      =
  751.         (InfoDataPtr->id_NumBlocks - InfoDataPtr->id_NumBlocksUsed) *
  752.          InfoDataPtr->id_BytesPerBlock;
  753.         size.capacity  =
  754.          InfoDataPtr->id_NumBlocks *
  755.          InfoDataPtr->id_BytesPerBlock;
  756.     } else
  757.     {   rq("Can't get volume info!");
  758.     }
  759.     FreeVec(InfoDataPtr);
  760.     // InfoDataPtr = NULL;
  761.  
  762.     comma(size.blocksize, commastring);
  763.     SetGadgetAttrs // "dirs"
  764.     (   size_gadgets[GID_8_ST8], MainWindowPtr, NULL,
  765.         STRINGA_TextVal, commastring,
  766.         TAG_END
  767.     );
  768.  
  769.     /* 4: Now we are ready to begin the main part of the operation.
  770.  
  771.     size.topdir[]     = the 'owning' top-level directory for this subdir.
  772.                         Top-level dirs are owned by themselves.
  773.     size.bytes[]      = the size of this top-level directory/file.
  774.     size.entries      = how many top-level dirs, ie. how many names in the
  775.                         listview gadget.
  776.     size.path         = the path (drive, partition, etc.) the user is doing
  777.                         the report on.
  778.     size.stackentries = the current size of the stack.
  779.     DirNamesAllocated = the number of allocated chunks for the
  780.                         topdir names. */
  781.  
  782.     if (!(        StackPtr = AllocVec(LIMIT_DIRS * sizeof(STRPTR), NULL)))
  783.     {   rq("Out of memory!");
  784.     }
  785.  
  786.     files = size.total = 0;
  787.     if (size.finddup)
  788.     {   if (!( PathnamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  789.         {   rq("Out of memory!");
  790.         }
  791.         if (!( FilenamePtr = AllocVec(MAX_FILES * sizeof(STRPTR), NULL)))
  792.         {   rq("Out of memory!");
  793.         }
  794.         if (!(       IsDup = AllocVec(MAX_FILES * sizeof(ABOOL) , NULL)))
  795.         {   rq("Out of memory!");
  796.     }   }
  797.  
  798.     // This must be allocated with AllocDosObject()
  799.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  800.     {   rq("Can't allocate DOS object!");
  801.     }
  802.  
  803.     eac->eac_LastKey = 0;
  804.     do
  805.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 4096, ED_SIZE, eac);
  806.         if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  807.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  808.             eac = NULL;
  809.             rq("Can't examine path!");
  810.         }
  811.         if (eac->eac_Entries == 0)
  812.         {   ; /* ExAll() failed normally with no entries */
  813.             continue; /* more is USUALLY zero */
  814.         }
  815.  
  816.         // OK, ExAll() has generated up to 2K of data.
  817.         ead = (struct ExAllData *) EADataPtr;
  818.         do
  819.         {   /* use ead here */
  820.  
  821.             if (ead->ed_Type == -3 || ead->ed_Type == 2) // if a normal file or normal directory (ie. not a link)
  822.             {   size.entries++;
  823.                 if (size.entries == LIMIT_DIRS)
  824.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  825.                     eac = NULL;
  826.                     rq("Overflow!");
  827.                 }
  828.                 size.type[size.entries] = ead->ed_Type;
  829.                 if (size.entries > DirNamesAllocated)
  830.                 {   if (!(DirNamePtr[DirNamesAllocated + 1] = AllocMem(PATHNAMEFIELD, MEMF_PUBLIC)))
  831.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  832.                         eac = NULL;
  833.                         rq("Out of memory!");
  834.                     }
  835.                     DirNamesAllocated++;
  836.                 }
  837.                 strcpy(DirNamePtr[size.entries], ead->ed_Name);
  838.                 if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  839.                 {   size.numdirs++;
  840.                     if (!(size.numdirs % GRANULARITY_DIRS))
  841.                     {   comma(size.numdirs, commastring);
  842.                         SetGadgetAttrs
  843.                         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  844.                             STRINGA_TextVal, commastring,
  845.                             TAG_END
  846.                         );
  847.                     }
  848.                     size.bytes[size.entries] = 0;
  849.                     strcpy(tempstring, size.path);
  850.                     if (!AddPart(tempstring, ead->ed_Name, PATHNAMEFIELD))
  851.                     {   FreeDosObject(DOS_EXALLCONTROL, eac);
  852.                         eac = NULL;
  853.                         rq("Can't add filename to pathname!");
  854.                     }
  855.                     push(tempstring, size.entries);
  856.                 } else
  857.                 {   size.numfiles++;
  858.                     if (!(size.numfiles % GRANULARITY_FILES))
  859.                     {   comma(size.numfiles, commastring);
  860.                         SetGadgetAttrs
  861.                         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  862.                             STRINGA_TextVal, commastring,
  863.                             TAG_END
  864.                         );
  865.                     }
  866.                     addduplicate("", ead->ed_Name);
  867.                     if (size.slack)
  868.                     {   if (ead->ed_Size % size.blocksize == 0)
  869.                         {   size.bytes[size.entries] = (ead->ed_Size / size.blocksize) * size.blocksize;
  870.                             size.total              += (ead->ed_Size / size.blocksize) * size.blocksize;
  871.                         } else
  872.                         {   size.bytes[size.entries] = ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  873.                             size.total              += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  874.                     }   }
  875.                     else
  876.                     {   size.bytes[size.entries]     = ead->ed_Size;
  877.                         size.total                  += ead->ed_Size;
  878.             }   }   }
  879.  
  880.             /* get next ead */
  881.             ead = ead->ed_Next;
  882.         } while(ead);
  883.     } while(more);
  884.  
  885.     FreeDosObject(DOS_EXALLCONTROL, eac);
  886.     // eac = NULL;
  887.     UnLock(DirHandle);
  888.     DirHandle = NULL;
  889.  
  890.     SetGadgetAttrs
  891.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  892.         FUELGAUGE_Min,   0,
  893.         FUELGAUGE_Max,   100,
  894.         FUELGAUGE_Level, 50,
  895.         GA_Text,         "Reading subdirectories...",
  896.         TAG_END
  897.     );
  898.     pop();
  899.  
  900.     // Now handle the list.
  901.     killsizelist();
  902.     if (status == STATUS_BUSY)
  903.     {   /* size.entries is the actual number of entries. The array elements are
  904.         from 1 to size.entries.
  905.  
  906.         bubble sort routine */
  907.  
  908.         SetGadgetAttrs
  909.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  910.             FUELGAUGE_Min,   0,
  911.             FUELGAUGE_Max,   size.entries - 2,
  912.             GA_Text,         "Sorting contents...",
  913.             TAG_END
  914.         );
  915.         setbar(size.entries - 2);
  916.  
  917.         for (i = size.entries; i >= 2; i--)
  918.         {   progressbar(size.entries - 1);
  919.  
  920.             for (j = 2; j <= i; j++)
  921.             {   if (size.bytes[j - 1] < size.bytes[j]) 
  922.                 {   // swap them
  923.                     tempbytes = size.bytes[j - 1];
  924.                     size.bytes[j - 1] = size.bytes[j]; 
  925.                     size.bytes[j] = tempbytes;
  926.                     temptype = size.type[j - 1];
  927.                     size.type[j - 1] = size.type[j];
  928.                     size.type[j] = temptype;
  929.                     strcpy(tempname, DirNamePtr[j - 1]);
  930.                     strcpy(DirNamePtr[j - 1], DirNamePtr[j]);
  931.                     strcpy(DirNamePtr[j], tempname);
  932.         }   }   }
  933.  
  934.         getdate();
  935.         if (size.log)
  936.         {   strcpy(logstring, "Path: \"");
  937.             strcat(logstring, size.path);
  938.             strcat(logstring, "\" at ");
  939.             strcat(logstring, timestring);
  940.             strcat(logstring, " on ");
  941.             strcat(logstring, weekdaystring);
  942.             strcat(logstring, " ");
  943.             strcat(logstring, datestring);
  944.             strcat(logstring, ":\n");
  945.             if (!(LogFileHandle = (BPTR) Open(size.logfile, MODE_READWRITE)))
  946.                 rq("Can't open file for appending!");
  947.             Seek(LogFileHandle, 0, OFFSET_END);
  948.             writeline();
  949.         }
  950.  
  951.         for (i = 1; i <= size.entries; i++)
  952.         {   scale(size.bytes[i]);
  953.  
  954.             if (size.log)
  955.             {   if (size.type[i] == 2)
  956.                 {   strcpy(logstring, "*");
  957.                 } else
  958.                 {   strcpy(logstring, " ");
  959.                 }
  960.                 strncat(logstring, DirNamePtr[i], TRUNCATE);
  961.                 if (strlen(DirNamePtr[i]) < TRUNCATE)
  962.                 {   length = TRUNCATE - strlen(DirNamePtr[i]);
  963.                     for (j = 1; j <= length; j++)
  964.                     {   strcat(logstring, " ");
  965.                 }   }
  966.                 strcat(logstring, " ");
  967.                 strcat(logstring, commastring);
  968.                 strcat(logstring, "\n");
  969.                 writeline();
  970.             }
  971.  
  972.             if (size.type[i] == 2)
  973.             {   strcpy(liststring[0], "*");
  974.             } else
  975.             {   strcpy(liststring[0], " ");
  976.             }
  977.             strcat(liststring[0], DirNamePtr[i]);
  978.             for (j = 0; j <= 13; j++)
  979.             {   if (commastring[j] != ' ')
  980.                 {   where = j; // where is index of first non-space character
  981.                     break;
  982.             }   }
  983.             strcpy(liststring[1], &commastring[where]);
  984.  
  985.             if (!(ListBrowserNodePtr = AllocListBrowserNode
  986.             (   2,                       // columns,
  987.                 LBNA_Column,             0,
  988.                     LBNCA_CopyText,      TRUE,
  989.                     LBNCA_Text,          liststring[0],
  990.                 LBNA_Column,             1,
  991.                     LBNCA_CopyText,      TRUE,
  992.                     LBNCA_Text,          &commastring[where],
  993.                     LBNCA_Justification, LCJ_RIGHT,
  994.                 TAG_END
  995.             )))
  996.             {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  997.             }
  998.  
  999.             AddTail(&SizeList, ListBrowserNodePtr); // AddTail() has no return code
  1000.             SizeNodes = TRUE;
  1001.         }
  1002.  
  1003.         scale(size.total);
  1004.         SetGadgetAttrs // "used in path"
  1005.         (   size_gadgets[GID_8_ST4], MainWindowPtr, NULL,
  1006.             STRINGA_TextVal, commastring,
  1007.             TAG_END
  1008.         );
  1009.         scale(size.free);
  1010.         SetGadgetAttrs // "free on volume"
  1011.         (   size_gadgets[GID_8_ST5], MainWindowPtr, NULL,
  1012.             STRINGA_TextVal, commastring,
  1013.             TAG_END
  1014.         );
  1015.         scale(size.capacity);
  1016.         SetGadgetAttrs // "volume capacity"
  1017.         (   size_gadgets[GID_8_ST3], MainWindowPtr, NULL,
  1018.             STRINGA_TextVal, commastring,
  1019.             TAG_END
  1020.         );
  1021.         comma(size.numfiles, commastring);
  1022.         SetGadgetAttrs // "files"
  1023.         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1024.             STRINGA_TextVal, commastring,
  1025.             TAG_END
  1026.         );
  1027.         comma(size.numdirs, commastring);
  1028.         SetGadgetAttrs // "dirs"
  1029.         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1030.             STRINGA_TextVal, commastring,
  1031.             TAG_END
  1032.         );
  1033.  
  1034.         if (size.log)
  1035.         {   strcpy(logstring, "\nUsed in path:                            ");
  1036.             scale(size.total);
  1037.             strcat(logstring, commastring);
  1038.             strcat(logstring, "\nFree on volume:                          "); // these must be adjusted according to TRUNCATE
  1039.             scale(size.free);
  1040.             strcat(logstring, commastring);
  1041.             strcat(logstring, "\nVolume capacity:                         "); // these must be adjusted according to TRUNCATE
  1042.             scale(size.capacity);
  1043.             strcat(logstring, commastring);
  1044.             strcat(logstring, "\nFiles:                                   "); // these must be adjusted according to TRUNCATE
  1045.             comma(size.numfiles, commastring);
  1046.             strcat(logstring, commastring);
  1047.             strcat(logstring, "\nDirectories:                             "); // these must be adjusted according to TRUNCATE
  1048.             comma(size.numdirs, commastring);
  1049.             strcat(logstring, commastring);
  1050.             strcat(logstring, "\nBlock size:                              "); // these must be adjusted according to TRUNCATE
  1051.             comma(size.blocksize, commastring);
  1052.             strcat(logstring, commastring);
  1053.             strcat(logstring, "\n\n");
  1054.             writeline();
  1055.         }
  1056.  
  1057.         SetGadgetAttrs
  1058.         (   size_gadgets[GID_8_LB2], MainWindowPtr, NULL,
  1059.             LISTBROWSER_Labels, &SizeList,
  1060.             TAG_END
  1061.         );
  1062.         showduplicates();
  1063.     } else
  1064.     {   SetGadgetAttrs // "used in path"
  1065.         (   size_gadgets[GID_8_ST4], MainWindowPtr, NULL,
  1066.             STRINGA_TextVal, "-",
  1067.             TAG_END
  1068.         );
  1069.         SetGadgetAttrs // "free on volume"
  1070.         (   size_gadgets[GID_8_ST5], MainWindowPtr, NULL,
  1071.             STRINGA_TextVal, "-",
  1072.             TAG_END
  1073.         );
  1074.         SetGadgetAttrs // "volume capacity"
  1075.         (   size_gadgets[GID_8_ST3], MainWindowPtr, NULL,
  1076.             STRINGA_TextVal, "-",
  1077.             TAG_END
  1078.         );
  1079.         SetGadgetAttrs // "files"
  1080.         (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1081.             STRINGA_TextVal, "-",
  1082.             TAG_END
  1083.         );
  1084.         SetGadgetAttrs // "directories"
  1085.         (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1086.             STRINGA_TextVal, "-",
  1087.             TAG_END
  1088.         );
  1089.         SetGadgetAttrs // "block size"
  1090.         (   size_gadgets[GID_8_ST8], MainWindowPtr, NULL,
  1091.             STRINGA_TextVal, "-",
  1092.             TAG_END
  1093.         );
  1094.         killsizelist();
  1095.         killduplist();
  1096.     }
  1097.  
  1098.     unghost();
  1099.     SetGadgetAttrs
  1100.     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1101.         FUELGAUGE_Min,     0,
  1102.         FUELGAUGE_Max,   100,
  1103.         FUELGAUGE_Level, 100,
  1104.         GA_Text,         "Done",
  1105.         TAG_END
  1106.     );
  1107.  
  1108.     if (LogFileHandle)
  1109.     {   Close(LogFileHandle);
  1110.         LogFileHandle = NULL;
  1111.     }
  1112.     while (FileNamesAllocated)
  1113.     {   FreeMem(StackPtr[FileNamesAllocated], PATHNAMEFIELD);
  1114.         StackPtr[FileNamesAllocated--] = NULL;
  1115.     }
  1116.     FreeVec(StackPtr);
  1117.     StackPtr = NULL;
  1118.  
  1119.     // We need the DirNamePtr[] array to remain valid, because
  1120.     // the user can click on the listview gadget.
  1121. }
  1122.  
  1123. MODULE void subdir(ULONG topdir)
  1124. {   BOOL                 more;
  1125.     TEXT                 tempstring[PATHNAMEFIELD + 1];
  1126.     struct ExAllControl* eac;
  1127.     struct ExAllData*    ead;
  1128.  
  1129.     /* Instead of passing a pointer to the path, we use a global string.
  1130.     There are memory corruption problems if you pass pointers to variables
  1131.     which are really local to other functions.
  1132.  
  1133.     This is dynamically allocated as it must be at least word-aligned;
  1134.     also remember not to allocate large arrays on the stack. */
  1135.  
  1136.     if (!(DirHandle = (BPTR) Lock(globalname, ACCESS_READ)))
  1137.     {   DisplayBeep(ScreenPtr);
  1138.         return;
  1139.     }
  1140.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  1141.     {   UnLock(DirHandle);
  1142.         DirHandle = NULL;
  1143.         rq("Can't allocate DOS object!");
  1144.     }
  1145.  
  1146.     eac->eac_LastKey = 0;
  1147.     do
  1148.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 4096, ED_SIZE, eac);
  1149.         if ((!more) && (IoErr() != ERROR_NO_MORE_ENTRIES))
  1150.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1151.             eac = NULL;
  1152.             UnLock(DirHandle);
  1153.             DirHandle = NULL;
  1154.             rq("Can't examine path!");
  1155.         }
  1156.         if (eac->eac_Entries == 0)
  1157.         {   ; /* ExAll() failed normally with no entries */
  1158.             continue; /* more is USUALLY zero */
  1159.         }
  1160.         ead = (struct ExAllData *) EADataPtr;
  1161.  
  1162.         do
  1163.         {   /* use ead here */
  1164.  
  1165.             if (ead->ed_Type == 2) /* +2 is dir, +3 is softlink, -3 is file */
  1166.             {   size.numdirs++;    
  1167.                 if (!(size.numdirs % GRANULARITY_DIRS))
  1168.                 {   comma(size.numdirs, commastring);
  1169.                     SetGadgetAttrs
  1170.                     (   size_gadgets[GID_8_ST7], MainWindowPtr, NULL,
  1171.                         STRINGA_TextVal, commastring,
  1172.                         TAG_END
  1173.                     );
  1174.                 }
  1175.                 strcpy(tempstring, globalname);
  1176.                 if (!AddPart(tempstring, ead->ed_Name, PATHNAMEFIELD))
  1177.                 {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1178.                     eac = NULL;
  1179.                     UnLock(DirHandle);
  1180.                     DirHandle = NULL;
  1181.                     rq("Can't add filename to pathname!");
  1182.                 }
  1183.                 push(tempstring, topdir);
  1184.             } elif (ead->ed_Type == -3) // if it's a file
  1185.             {   size.numfiles++;
  1186.                 if (!(size.numfiles % GRANULARITY_FILES))
  1187.                 {   comma(size.numfiles, commastring);
  1188.                     SetGadgetAttrs
  1189.                     (   size_gadgets[GID_8_ST6], MainWindowPtr, NULL,
  1190.                         STRINGA_TextVal, commastring,
  1191.                         TAG_END
  1192.                     );
  1193.                 }
  1194.                 addduplicate(&globalname[pathlength], ead->ed_Name);
  1195.                 if (size.slack)
  1196.                 {   if (ead->ed_Size % size.blocksize == 0)
  1197.                     {   size.bytes[topdir] += (ead->ed_Size / size.blocksize) * size.blocksize;
  1198.                         size.total         += (ead->ed_Size / size.blocksize) * size.blocksize;
  1199.                     } else
  1200.                     {   size.bytes[topdir] += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  1201.                         size.total         += ((ead->ed_Size / size.blocksize) + 1) * size.blocksize;
  1202.                 }   }
  1203.                 else
  1204.                 {   size.bytes[topdir]     += ead->ed_Size;
  1205.                     size.total             += ead->ed_Size;
  1206.             }   }
  1207.  
  1208.             /* get next ead */
  1209.             ead = ead->ed_Next;
  1210.         } while(ead);
  1211.     } while(more);
  1212.  
  1213.     FreeDosObject(DOS_EXALLCONTROL, eac);
  1214.     // eac = NULL;
  1215.     UnLock(DirHandle);
  1216.     DirHandle = NULL;
  1217.     // don't call pop() yourself!
  1218. }
  1219.  
  1220. MODULE void pop(void)
  1221. {   ULONG breakval;
  1222.  
  1223.     pathlength = strlen(size.path);
  1224.     while (size.stackentries && status == STATUS_BUSY)
  1225.     {   size.stackentries--;
  1226.         strcpy(globalname, StackPtr[size.stackentries + 1]);
  1227.         subdir(size.topdir[size.stackentries + 1]);
  1228.         breakval = ra_checkbreak();
  1229.         if (breakval == 2)
  1230.             cleanexit(EXIT_SUCCESS);
  1231.         elif (breakval == 1)
  1232.             status = STATUS_STOPPING;
  1233. }   }
  1234. MODULE void push(STRPTR name, ULONG theindex)
  1235. {   size.stackentries++;
  1236.     if (size.stackentries == LIMIT_DIRS)
  1237.         rq("Overflow!");
  1238.     if (size.stackentries > FileNamesAllocated)
  1239.     {   if (!(StackPtr[FileNamesAllocated + 1] = AllocMem(PATHNAMEFIELD, MEMF_PUBLIC)))
  1240.             rq("Out of memory!");
  1241.         FileNamesAllocated++;
  1242.     }
  1243.     strcpy(StackPtr[size.stackentries], name);
  1244.     size.topdir[size.stackentries] = theindex;
  1245. }
  1246.  
  1247. AGLOBAL void size_loop(ULONG gid)
  1248. {   ULONG  code;
  1249.     STRPTR stringptr;
  1250.  
  1251.     switch(gid)
  1252.     {
  1253.     case GID_8_BU1: // path ASL
  1254.         pathasl();
  1255.     break;
  1256.     case GID_8_BU3:
  1257.         asl("~(#?.info)");
  1258.         SetGadgetAttrs // `Log to file:' (string)
  1259.         (   size_gadgets[GID_8_ST2], MainWindowPtr, NULL,
  1260.             STRINGA_TextVal, size.logfile,
  1261.         TAG_END);
  1262.     break;
  1263.     case GID_8_BU4: // update
  1264.         updatesize();
  1265.     break;
  1266.     // GID_8_BU5 is stop
  1267.     case GID_8_BU6:
  1268.         root();
  1269.     break;
  1270.     case GID_8_BU7:
  1271.         parent();
  1272.     break;
  1273.     case GID_8_ST1: // path string
  1274.         if (!(GetAttr
  1275.         (   STRINGA_TextVal, size_gadgets[GID_8_ST1], (ULONG *) &stringptr
  1276.         )))
  1277.         {   rq("Unsupported inquiry!"); // should never happen
  1278.         }
  1279.         strcpy(size.path, stringptr);
  1280.         updatesize();
  1281.     break;
  1282.     case GID_8_ST2: // output string
  1283.         if (!(GetAttr
  1284.         (   STRINGA_TextVal, size_gadgets[GID_8_ST2], (ULONG *) &stringptr
  1285.         )))
  1286.         {   rq("Unsupported inquiry!"); // should never happen
  1287.         }
  1288.         strcpy(size.logfile, stringptr);
  1289.     break;
  1290.     case GID_8_CB1:
  1291.         if (!(GetAttr
  1292.         (   GA_Selected, size_gadgets[GID_8_CB1], &size.log
  1293.         )))
  1294.         {   rq("Unsupported inquiry!"); // should never happen
  1295.         }
  1296.  
  1297.         SetGadgetAttrs // `Log to file:' (string)
  1298.         (   size_gadgets[GID_8_ST2], MainWindowPtr, NULL,
  1299.             GA_Disabled, !size.log,
  1300.             TAG_END
  1301.         );
  1302.         /* For some reason, we need to explicitly refresh the string gadget
  1303.         visuals here */
  1304.         RefreshGadgets((struct Gadget *) size_gadgets[GID_8_ST2], MainWindowPtr, NULL);
  1305.  
  1306.         SetGadgetAttrs // `Log to file:' (ASL button)
  1307.         (   size_gadgets[GID_8_BU3], MainWindowPtr, NULL,
  1308.             GA_Disabled, !size.log,
  1309.             TAG_END
  1310.         );
  1311.         if (size.log)
  1312.         {   ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST2]);
  1313.         }
  1314.     break;
  1315.     case GID_8_CB2:
  1316.         if (!(GetAttr
  1317.         (   GA_Selected, size_gadgets[GID_8_CB2], (ULONG *) &size.slack
  1318.         )))
  1319.         {   rq("Unsupported inquiry!"); // should never happen
  1320.         }
  1321.     break;
  1322.     case GID_8_CB3:
  1323.         if (!(GetAttr
  1324.         (   GA_Selected, size_gadgets[GID_8_CB3], (ULONG *) &size.finddup
  1325.         )))
  1326.         {   rq("Unsupported inquiry!"); // should never happen
  1327.         }
  1328.         SetGadgetAttrs
  1329.         (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1330.             GA_Disabled, !size.finddup,
  1331.             TAG_END
  1332.         );
  1333.     break;
  1334.     case GID_8_CH1:
  1335.         if (!(GetAttr
  1336.         (   CHOOSER_Selected, size_gadgets[GID_8_CH1], (ULONG *) &size.view
  1337.         )))
  1338.         {   rq("Unsupported inquiry!"); // should never happen
  1339.         }
  1340.     break;
  1341.     case GID_8_LB2:
  1342.         /* code is the position within the list, starting from 0. */
  1343.  
  1344.         if (!(GetAttr
  1345.         (   LISTBROWSER_Selected, size_gadgets[GID_8_LB2], (ULONG *) &code
  1346.         )))
  1347.         {   rq("Unsupported inquiry!"); // should never happen
  1348.         }
  1349.         code++;
  1350.         if (code <= size.entries && size.type[code] == 2)
  1351.         {   if (!(AddPart(size.path, DirNamePtr[code], PATHNAMEFIELD + 1)))
  1352.             {   rq("Can't add filename to pathname!");
  1353.             } else
  1354.             {   updatesize();
  1355.         }   }
  1356.     break;
  1357.     default:
  1358.     break;
  1359. }   }
  1360.  
  1361. AGLOBAL void size_exit(void)
  1362. {   if (TempHandle)
  1363.     {   UnLock(TempHandle);
  1364.         TempHandle = NULL;
  1365.     }
  1366.     if (DirHandle)
  1367.     {   UnLock(DirHandle);
  1368.         DirHandle = NULL;
  1369.     }
  1370.     if (LogFileHandle)
  1371.     {   Close(LogFileHandle);
  1372.         LogFileHandle = NULL;
  1373.     }
  1374.  
  1375.     // Only call this if the list gadget is detached or not present.
  1376.     // (ie. after closewindow()).
  1377.     if (SizeNodes)
  1378.     {   clearreactionlist(&SizeList);
  1379.         SizeNodes = FALSE;
  1380.     }
  1381.     if (DupNodes)
  1382.     {   clearreactionlist(&DupList);
  1383.         DupNodes = FALSE;
  1384.     }
  1385.  
  1386.     while (FileNamesAllocated)
  1387.     {   FreeMem(StackPtr[FileNamesAllocated], PATHNAMEFIELD);
  1388.         StackPtr[FileNamesAllocated--] = NULL;
  1389.     }
  1390.     if (StackPtr)
  1391.     {   FreeVec(StackPtr);
  1392.         StackPtr = NULL;
  1393.     }
  1394.     while ( DirNamesAllocated)
  1395.     {   FreeMem(DirNamePtr[DirNamesAllocated], PATHNAMEFIELD);
  1396.         DirNamePtr[DirNamesAllocated--] = NULL;
  1397.     }
  1398.     if (DirNamePtr)
  1399.     {   FreeVec(DirNamePtr);
  1400.         DirNamePtr = NULL;
  1401. }   }
  1402.  
  1403. AGLOBAL void size_die(void)
  1404. {   if (EmptySizeNodes)
  1405.     {   clearreactionlist(&EmptySizeList);
  1406.         EmptySizeNodes = FALSE;
  1407.     }
  1408.     if (EmptyDupNodes)
  1409.     {   clearreactionlist(&EmptyDupList);
  1410.         EmptyDupNodes = FALSE;
  1411.     }
  1412.     IOBuffer[0]  = (UBYTE) size.log;
  1413.     IOBuffer[6]  = (UBYTE) size.finddup;
  1414.     IOBuffer[21] = (UBYTE) size.slack;
  1415.     IOBuffer[22] = (UBYTE) size.view;
  1416. }
  1417.  
  1418. AGLOBAL void size_config(void)
  1419. {   size.log     = (ULONG) IOBuffer[0];
  1420.     size.finddup = (ULONG) IOBuffer[6];
  1421.     size.slack   = (ULONG) IOBuffer[21];
  1422.     size.view    = (ULONG) IOBuffer[22];
  1423. }
  1424.  
  1425. MODULE void parent(void)
  1426. {   BPTR DirHandle,
  1427.          ParentHandle;
  1428.  
  1429.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1430.         rq("Can't lock directory!");
  1431.     if (!(ParentHandle = ParentDir(DirHandle)))
  1432.     {   /* It returned a NULL lock; ie. a lock on SYS:
  1433.         That is not what we want. */
  1434.         ParentHandle = DirHandle;
  1435.     }
  1436.     if (!NameFromLock(ParentHandle, size.path, PATHNAMEFIELD))
  1437.         rq("Can't get name from lock!");
  1438.     UnLock(DirHandle);
  1439.     // DirHandle = NULL;
  1440.  
  1441.     updatesize();
  1442. }
  1443.  
  1444. MODULE void root(void)
  1445. {   BPTR  DirHandle,
  1446.           ParentHandle;
  1447.     ABOOL rootdone     = FALSE;
  1448.  
  1449.     if (!(DirHandle = (BPTR) Lock(size.path, ACCESS_READ)))
  1450.         rq("Can't lock directory!");
  1451.     do
  1452.     {   if (!(ParentHandle = ParentDir(DirHandle)))
  1453.         {   /* It returned a NULL lock; ie. a lock on SYS:
  1454.                That is not what we want. */
  1455.             ParentHandle = DirHandle;
  1456.             rootdone = TRUE;
  1457.         } else DirHandle = ParentHandle;
  1458.     } while (!rootdone);
  1459.     if (!NameFromLock(ParentHandle, size.path, PATHNAMEFIELD))
  1460.         rq("Can't get name from lock!");
  1461.     UnLock(DirHandle);
  1462.     // DirHandle = NULL;
  1463.  
  1464.     updatesize();
  1465. }
  1466.  
  1467. MODULE void pathasl(void)
  1468. {   strcpy(asldir, size.path);
  1469.     if (dirasl()) // path for ASL must be valid?
  1470.     {   strcpy(size.path, aslresult);
  1471.         SetGadgetAttrs
  1472.         (   size_gadgets[GID_8_ST1], MainWindowPtr, NULL,
  1473.             STRINGA_TextVal, size.path,
  1474.             TAG_END
  1475.         );
  1476.         updatesize();
  1477. }   }
  1478.  
  1479. MODULE void showduplicates(void)
  1480. {   ABOOL                 found = FALSE,
  1481.                           started = FALSE,
  1482.                           success;
  1483.     TEXT                  pathnamestring[PATHNAMEFIELD + 1],
  1484.                           commandstring[PATHNAMEFIELD + 1],
  1485.                           lastfilename[PATHNAMEFIELD + 1];
  1486.     ULONG                 breakval, i, j, k, where,
  1487.                           firstpen, secondpen, currentpen, dups;
  1488.     LONG                  length;
  1489.     STRPTR                tempPathnamePtr, tempFilenamePtr;
  1490.     struct DateTime       DateTime;
  1491.     struct FileInfoBlock* FIBPtr;
  1492.     struct Node*          ListBrowserNodePtr;
  1493.  
  1494.     DateTime.dat_Format  = FORMAT_DOS;
  1495.     DateTime.dat_Flags   = NULL;
  1496.     DateTime.dat_StrDay  = NULL;
  1497.     DateTime.dat_StrDate = datestring;
  1498.     DateTime.dat_StrTime = timestring;
  1499.  
  1500.     if (size.finddup)
  1501.     {   killduplist();
  1502.  
  1503.         lockscreen();
  1504.         firstpen = FindColor
  1505.         (   ScreenPtr->ViewPort.ColorMap,
  1506.             0xDDDDDDDD,
  1507.             0xDDDDDDDD,
  1508.             0xDDDDDDDD,
  1509.             -1
  1510.         );
  1511.         secondpen = FindColor
  1512.         (   ScreenPtr->ViewPort.ColorMap,
  1513.             0xAAAAAAAA,
  1514.             0xAAAAAAAA,
  1515.             0xAAAAAAAA,
  1516.            -1
  1517.         );
  1518.         unlockscreen();
  1519.         currentpen = firstpen;
  1520.  
  1521.         if (size.log)
  1522.         {   strcpy(logstring, "Duplicates found:\n");
  1523.             writeline();
  1524.         }
  1525.  
  1526.         /* Now we iterate through the complete file list (last entry index
  1527.         of files). For each file (i), we look at every other file (j). As
  1528.         soon as we find a matching file, we add the file (i) to the
  1529.         duplicate file list. */
  1530.  
  1531.         SetGadgetAttrs
  1532.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1533.             FUELGAUGE_Min,   1,
  1534.             FUELGAUGE_Max,   files,
  1535.             GA_Text,         "Matching duplicates...",
  1536.             TAG_DONE
  1537.         );
  1538.         setbar(files);
  1539.  
  1540.         for (i = 1; i <= files; i++)
  1541.         {   progressbar(i);
  1542.             breakval = ra_checkbreak();
  1543.             if (breakval == 2)
  1544.             {   cleanexit(EXIT_SUCCESS);
  1545.             } elif (breakval == 1)
  1546.             {   status = STATUS_STOPPING;
  1547.                 SetGadgetAttrs
  1548.                 (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1549.                     GA_Text, "Stopping...",
  1550.                     TAG_END
  1551.                 );
  1552.                 break;
  1553.             }
  1554.             // if the user doesn't want us to stop...
  1555.             for (j = 1; j <= files; j++)
  1556.             {   if (i != j && !stricmp(FilenamePtr[i], FilenamePtr[j]))
  1557.                 {   found = TRUE; // we found (at least one) match
  1558.                     IsDup[i] = TRUE;
  1559.                     break;
  1560.         }   }   }
  1561.  
  1562.         if (status == STATUS_BUSY)
  1563.         {   SetGadgetAttrs
  1564.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1565.                 FUELGAUGE_Min,   1,
  1566.                 FUELGAUGE_Max,   files,
  1567.                 GA_Text,         "Condensing duplicates...",
  1568.                 TAG_END
  1569.             );
  1570.             setbar(files);
  1571.  
  1572.             // condense list
  1573.             dups = 0;
  1574.             for (i = 1; i <= files; i++)
  1575.             {   progressbar(i);
  1576.  
  1577.                 if (IsDup[i])
  1578.                 {   dups++;
  1579.                     FilenamePtr[dups] = FilenamePtr[i];
  1580.                     PathnamePtr[dups] = PathnamePtr[i];
  1581.                     IsDup[dups]       = IsDup[i];
  1582.                 } else
  1583.                 {   FreeVec(PathnamePtr[i]);
  1584.                     FreeVec(FilenamePtr[i]);
  1585.             }   }
  1586.  
  1587.             SetGadgetAttrs
  1588.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1589.                 FUELGAUGE_Min,   2,
  1590.                 FUELGAUGE_Max,   dups,
  1591.                 GA_Text,         "Sorting duplicates...",
  1592.                 TAG_END
  1593.             );
  1594.             setbar(dups);
  1595.  
  1596.             // bubble sort routine
  1597.             for (i = dups; i >= 2; i--)
  1598.             {   progressbar(dups - i);
  1599.                 for (j = 2; j <= i; j++)
  1600.                 {   if (stricmp(FilenamePtr[j - 1], FilenamePtr[j]) > 0)
  1601.                     {   // swap them
  1602.                         tempPathnamePtr     = PathnamePtr[j - 1];
  1603.                         PathnamePtr[j - 1]  = PathnamePtr[j];
  1604.                         PathnamePtr[j]      = tempPathnamePtr;
  1605.                         tempFilenamePtr     = FilenamePtr[j - 1];
  1606.                         FilenamePtr[j - 1]  = FilenamePtr[j];
  1607.                         FilenamePtr[j]      = tempFilenamePtr;
  1608.             }   }   }
  1609.  
  1610.             SetGadgetAttrs
  1611.             (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1612.                 FUELGAUGE_Min,   0,
  1613.                 FUELGAUGE_Max,   dups,
  1614.                 FUELGAUGE_Level, 0,
  1615.                 GA_Text,         "Examining duplicates...",
  1616.                 TAG_END
  1617.             );
  1618.             setbar(dups);
  1619.  
  1620.             NewList(&DupList);
  1621.  
  1622.             for (i = 1; i <= dups; i++)
  1623.             {   progressbar(i);
  1624.                 breakval = ra_checkbreak();
  1625.                 if (breakval == 2)
  1626.                 {   cleanexit(EXIT_SUCCESS);
  1627.                 } elif (breakval == 1)
  1628.                 {   status = STATUS_STOPPING;
  1629.                     SetGadgetAttrs
  1630.                     (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  1631.                         GA_Text,         "Stopping...",
  1632.                         TAG_END
  1633.                     );
  1634.                     break;
  1635.                 }
  1636.  
  1637.                 // begin creating the line of text
  1638.                 if (PathnamePtr[i][0] == '/')
  1639.                 {   strcpy(liststring[0], &(PathnamePtr[i][1]));
  1640.                 } else
  1641.                 {   strcpy(liststring[0], PathnamePtr[i]);
  1642.                 }
  1643.                 strcpy(logstring, " ");
  1644.                 strcat(logstring, liststring[0]);
  1645.                 if (strlen(logstring) > TRUNCATE)
  1646.                 {   *(logstring + TRUNCATE) = 0; // truncate
  1647.                 }
  1648.                 length = TRUNCATE + 2 - strlen(logstring);
  1649.                 if (length >= 1)
  1650.                 {   for (k = 1; k <= length; k++)
  1651.                     {   strcat(logstring, " ");
  1652.                 }   }
  1653.  
  1654.                 strcpy(pathnamestring, size.path);
  1655.                 if (PathnamePtr[i][0] != '/')
  1656.                 {   if (!AddPart(pathnamestring, PathnamePtr[i], 256))
  1657.                     {   rq("AddPart() failed!");
  1658.                 }   }
  1659.                 else
  1660.                 {   if (!AddPart(pathnamestring, &PathnamePtr[i][1], 256))
  1661.                     {   rq("AddPart() failed!");
  1662.                 }   }
  1663.                 success = FALSE;
  1664.  
  1665.                 // now get size and date of file
  1666.                 if (DirHandle  = (BPTR) Lock(pathnamestring, ACCESS_READ))
  1667.                 {   if (FIBPtr =        AllocDosObject(DOS_FIB, NULL))
  1668.                     {   success = TRUE;
  1669.  
  1670.                         if (Examine(DirHandle, FIBPtr))
  1671.                         {   comma(FIBPtr->fib_Size, commastring);
  1672.                             strcat(logstring, commastring);
  1673.                             for (j = 0; j <= 13; j++)
  1674.                             {   if (commastring[j] != ' ')
  1675.                                 {   where = j; // where is index of first non-space character
  1676.                                     break;
  1677.                             }   }
  1678.                             strcpy(liststring[1], &commastring[where]);
  1679.                         } else
  1680.                         {   strcpy(liststring[1], "?");
  1681.                             strcat(logstring, "            ?");
  1682.                         }
  1683.                         strcat(logstring, " ");
  1684.  
  1685.                         DateTime.dat_Stamp   = FIBPtr->fib_Date;
  1686.                         if (DateToStr(&DateTime))
  1687.                         {   strcpy(liststring[2], datestring);
  1688.                             strcpy(liststring[3], timestring);
  1689.                         } else
  1690.                         {   strcpy(liststring[2], "        ?");
  1691.                             strcpy(liststring[3], "        ?");
  1692.                         }
  1693.                         strcat(logstring, liststring[2]);
  1694.                         strcat(logstring, " ");
  1695.                         strcat(logstring, liststring[3]);
  1696.                         strcat(logstring, " ");
  1697.  
  1698.                         FreeDosObject(DOS_FIB, FIBPtr);
  1699.                         // FIBPtr = NULL;
  1700.                         UnLock(DirHandle);
  1701.                         DirHandle = NULL;
  1702.                 }   }
  1703.  
  1704.                 if (!success)
  1705.                 {   strcpy(liststring[1], "            ?");
  1706.                     strcpy(liststring[2], "            ?");
  1707.                     strcpy(liststring[3], "            ?");
  1708.                     strcat(logstring, liststring[1]);
  1709.                     strcat(logstring, " ");
  1710.                     strcat(logstring, liststring[2]);
  1711.                     strcat(logstring, " ");
  1712.                     strcat(logstring, liststring[3]);
  1713.                     strcat(logstring, " ");
  1714.                 }
  1715.  
  1716.                 getversion(pathnamestring, liststring[4]);
  1717.                 strcat(logstring, liststring[4]);
  1718.  
  1719.                 // now get the file version
  1720.                 if (ram)
  1721.                 {   strcpy(commandstring, "RAM:Version ");
  1722.                 } else
  1723.                 {   strcpy(commandstring, "Version ");
  1724.                 }
  1725.                 strcat(commandstring, pathnamestring);
  1726.                 strcat(commandstring, " >T:ReportPlus.temp");
  1727.                 if (!SystemTags(commandstring, SYS_Output, Open("NIL:", MODE_NEWFILE), TAG_DONE))
  1728.                 {   readordie("T:ReportPlus.temp");
  1729.                     for (k = 0; k <= LONGESTFIELD; k++)
  1730.                     {   if (IOBuffer[k] == LF)
  1731.                         {   IOBuffer[k] = 0;
  1732.                             break;
  1733.                     }   }
  1734.                     strcpy(liststring[4], IOBuffer);
  1735.                 } else
  1736.                 {   strcpy(liststring[4], "?");
  1737.                 }
  1738.                 strcat(logstring, liststring[4]);
  1739.  
  1740.                 if (started)
  1741.                 {   if (stricmp(FilenamePtr[i], lastfilename))
  1742.                     {   if (currentpen == firstpen)
  1743.                         {   currentpen = secondpen;
  1744.                         } else currentpen = firstpen;
  1745.                 }   }
  1746.                 else started = TRUE;
  1747.  
  1748.                 if (!(ListBrowserNodePtr = AllocListBrowserNode
  1749.                 (   5,                       // columns,
  1750.                     LBNA_Column,             0,
  1751.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1752.                         LBNCA_FGPen,         BLACK,
  1753.                         LBNCA_BGPen,         currentpen,
  1754.                         LBNCA_CopyText,      TRUE,
  1755.                         LBNCA_Text,          liststring[0],
  1756.                     LBNA_Column,             1,
  1757.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1758.                         LBNCA_FGPen,         BLACK,
  1759.                         LBNCA_BGPen,         currentpen,
  1760.                         LBNCA_CopyText,      TRUE,
  1761.                         LBNCA_Text,          liststring[1],
  1762.                         LBNCA_Justification, LCJ_RIGHT,
  1763.                     LBNA_Column,             2,
  1764.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1765.                         LBNCA_FGPen,         BLACK,
  1766.                         LBNCA_BGPen,         currentpen,
  1767.                         LBNCA_CopyText,      TRUE,
  1768.                         LBNCA_Text,          liststring[2],
  1769.                     LBNA_Column,             3,
  1770.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1771.                         LBNCA_FGPen,         BLACK,
  1772.                         LBNCA_BGPen,         currentpen,
  1773.                         LBNCA_CopyText,      TRUE,
  1774.                         LBNCA_Text,          liststring[3],
  1775.                     LBNA_Column,             4,
  1776.                         LBNA_Flags,          LBFLG_CUSTOMPENS,
  1777.                         LBNCA_FGPen,         BLACK,
  1778.                         LBNCA_BGPen,         currentpen,
  1779.                         LBNCA_CopyText,      TRUE,
  1780.                         LBNCA_Text,          liststring[4],
  1781.                     TAG_END
  1782.                 )))
  1783.                 {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1784.                 }
  1785.                 AddTail(&DupList, ListBrowserNodePtr); // AddTail() has no return code
  1786.                 DupNodes = TRUE;
  1787.                 strcpy(lastfilename, FilenamePtr[i]);
  1788.                 
  1789.                 if (size.log) // write to logfile
  1790.                 {   strcat(logstring, "\n");
  1791.                     writeline();
  1792.             }   }
  1793.             for (i = 1; i <= dups; i++)
  1794.             {   FreeVec(PathnamePtr[i]);
  1795.                 FreeVec(FilenamePtr[i]);
  1796.         }   }
  1797.         else
  1798.         {   for (i = 1; i <= files; i++)
  1799.             {   FreeVec(PathnamePtr[i]);
  1800.                 FreeVec(FilenamePtr[i]);
  1801.         }   }
  1802.  
  1803.         files = 0;
  1804.         FreeVec(IsDup);
  1805.         IsDup = NULL;
  1806.         FreeVec(PathnamePtr);
  1807.         PathnamePtr = NULL;
  1808.         FreeVec(FilenamePtr);
  1809.         FilenamePtr = NULL;
  1810.         DeleteFile("T:ReportPlus.temp"); /* returns FALSE for failure */
  1811.  
  1812.         if (size.log)
  1813.         {   if (!found)
  1814.             {   strcpy(logstring, " None\n");
  1815.             }
  1816.             strcat(logstring, "\n");
  1817.             writeline();
  1818.         }
  1819.  
  1820.         SetGadgetAttrs
  1821.         (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1822.             LISTBROWSER_Labels, &DupList,
  1823.             TAG_END
  1824.         );
  1825. }   }
  1826.  
  1827. MODULE void addduplicate(STRPTR path, STRPTR filename)
  1828. {   TEXT tablestring[257];
  1829.  
  1830.     if (size.finddup)
  1831.     {   files++;
  1832.         if (files >= MAX_FILES)
  1833.         {   rq("Too many files!");
  1834.         }
  1835.         IsDup[files] = FALSE;
  1836.  
  1837.         if (!(FilenamePtr[files] = AllocVec(strlen(filename) + 1, NULL)))
  1838.         {   rq("Out of memory!");
  1839.         }
  1840.         strcpy(FilenamePtr[files], filename);
  1841.  
  1842.         strcpy(tablestring, path);
  1843.         if (!AddPart(tablestring, filename, 256))
  1844.         {   rq("AddPart() failed!");
  1845.         }
  1846.         if (!(PathnamePtr[files] = AllocVec(strlen(tablestring) + 1, NULL)))
  1847.         {   rq("Out of memory!");
  1848.         }
  1849.         strcpy(PathnamePtr[files], tablestring);
  1850.  
  1851.     /* size.path   path           filename    PathnamePtr[]           FilenamePtr[]
  1852.        "SYS:Tools" "Commodities/" "AutoPoint" "Commodities/AutoPoint" "AutoPoint" */
  1853. }   }
  1854.  
  1855. MODULE void writeline(void)
  1856. {   /* The file is opened just before the first call to writeline()
  1857.     (when the date, time, etc. is written). Then we keep the file open
  1858.     and do our scan. Then we write out the results a line at a time,
  1859.     then the free and total bytes.
  1860.       If we are also doing duplicates, we now do our thinking,
  1861.     write the results a line at a time, then close the file. */
  1862.  
  1863.     if (FPuts(LogFileHandle, logstring))
  1864.     {   Close(LogFileHandle);
  1865.         LogFileHandle = NULL;
  1866.         rq("Can't append to file!");
  1867. }   }
  1868.  
  1869. MODULE void killsizelist(void)
  1870. {   SetGadgetAttrs
  1871.     (   size_gadgets[GID_8_LB2], MainWindowPtr, NULL,
  1872.         LISTBROWSER_Labels, &EmptySizeList,
  1873.         TAG_END
  1874.     );
  1875.     if (SizeNodes)
  1876.     {   clearreactionlist(&SizeList);
  1877.         SizeNodes = FALSE;
  1878. }   }
  1879.  
  1880. MODULE void killduplist(void)
  1881. {   SetGadgetAttrs
  1882.     (   size_gadgets[GID_8_LB1], MainWindowPtr, NULL,
  1883.         LISTBROWSER_Labels, &EmptyDupList,
  1884.         TAG_END
  1885.     );
  1886.     if (DupNodes)
  1887.     {   clearreactionlist(&DupList);
  1888.         DupNodes = FALSE;
  1889. }   }
  1890.  
  1891. AGLOBAL ULONG Hook8Func(struct Hook *h, VOID *o, VOID *msg)
  1892. {   /* "When the hook is called, the data argument points to the
  1893.     window object and message argument to the IntuiMessage." */
  1894.  
  1895.     UWORD code, qual;
  1896.     ULONG scroll;
  1897.  
  1898.     geta4(); // wait till here before doing anything
  1899.     code = ((struct IntuiMessage *) msg)->Code;
  1900.     qual = ((struct IntuiMessage *) msg)->Qualifier;
  1901.     switch(code)
  1902.     {
  1903.     case SCAN_HELP:
  1904.         if (status == STATUS_READY)
  1905.         {   helpabout();
  1906.         }
  1907.     break;
  1908.     case SCAN_ESCAPE:
  1909.         if (status == STATUS_READY)
  1910.         {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1911.             {   cleanexit(EXIT_SUCCESS);
  1912.             } else page = 0;
  1913.         } else
  1914.         {   // assert(status == STATUS_BUSY);
  1915.             status = STATUS_STOPPING;
  1916.         }
  1917.     break;
  1918.     case SCAN_P:
  1919.         ActivateLayoutGadget(size_gadgets[GID_8_LY1], MainWindowPtr, NULL, (Object) size_gadgets[GID_8_ST1]);
  1920.     break;
  1921.     case SCAN_V:
  1922.         if (status == STATUS_READY)
  1923.         {   if (!(qual & IEQUALIFIER_LSHIFT) && !(qual & IEQUALIFIER_RSHIFT))
  1924.             {   if (size.view < UNITOPTIONS)
  1925.                     size.view++;
  1926.                 else size.view = 0;
  1927.             } else
  1928.             {   if (size.view > 0)
  1929.                     size.view--;
  1930.                 else size.view = UNITOPTIONS;
  1931.             }
  1932.             SetGadgetAttrs
  1933.             (   size_gadgets[GID_8_CH1], MainWindowPtr, NULL,
  1934.                 CHOOSER_Selected, size.view,
  1935.                 TAG_END
  1936.             );
  1937.         }
  1938.     break;
  1939.     case SCAN_PERIOD:
  1940.         pathasl();
  1941.     break;
  1942.     case SCAN_UP:
  1943.         if (qual & IEQUALIFIER_CONTROL)
  1944.         {   scroll = LBP_TOP;
  1945.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1946.         {   scroll = LBP_PAGEUP;
  1947.         } else scroll = LBP_LINEUP;
  1948.     break;
  1949.     case SCAN_DOWN:
  1950.         if (qual & IEQUALIFIER_CONTROL)
  1951.         {   scroll = LBP_BOTTOM;
  1952.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1953.         {   scroll = LBP_PAGEDOWN;
  1954.         } else scroll = LBP_LINEDOWN;
  1955.     break;
  1956.     default:
  1957.     break;
  1958.     }
  1959.  
  1960.     if (code == SCAN_UP || code == SCAN_DOWN)
  1961.     {   SetGadgetAttrs
  1962.         (   size_gadgets[GID_8_LB2],      // pointer to gadget
  1963.             MainWindowPtr,                // pointer to window (not window object!)
  1964.             NULL,                         // pointer to requester
  1965.             LISTBROWSER_Position, scroll, // tags
  1966.             TAG_DONE                      // done
  1967.         );
  1968.     }
  1969.  
  1970.     return(1);
  1971. }
  1972.  
  1973. MODULE void ghost(void)
  1974. {   status = STATUS_BUSY;
  1975.  
  1976.     SetGadgetAttrs // "update"
  1977.     (   size_gadgets[GID_8_BU4], MainWindowPtr, NULL,
  1978.         GA_Disabled, TRUE,
  1979.         TAG_END
  1980.     );
  1981.     SetGadgetAttrs // "stop"
  1982.     (   size_gadgets[GID_8_BU5], MainWindowPtr, NULL,
  1983.         GA_Disabled, FALSE,
  1984.         TAG_END
  1985.     );
  1986. }
  1987.  
  1988. MODULE void unghost(void)
  1989. {   status = STATUS_READY;
  1990.  
  1991.     SetGadgetAttrs // "update"
  1992.     (   size_gadgets[GID_8_BU4], MainWindowPtr, NULL,
  1993.         GA_Disabled, FALSE,
  1994.         TAG_END
  1995.     );
  1996.     SetGadgetAttrs // "stop"
  1997.     (   size_gadgets[GID_8_BU5], MainWindowPtr, NULL,
  1998.         GA_Disabled, TRUE,
  1999.         TAG_END
  2000.     );
  2001. }
  2002.  
  2003. MODULE void scale(ULONG bytes)
  2004. {   if (size.view == 0) // bytes
  2005.     {   comma(bytes, commastring);
  2006.     } elif (size.view == 1) // kilobytes
  2007.     {   comma(bytes / 1024, commastring);
  2008.     } elif (size.view == 2) // megabytes
  2009.     {   comma(bytes / 1048576, commastring);
  2010.     } else
  2011.     {   // assert(size.view == 3); // blocks
  2012.         // assert(size.blocksize); // to avoid division by zero
  2013.         comma(bytes / size.blocksize, commastring);
  2014.         if (bytes % size.blocksize)
  2015.         {   comma((bytes / size.blocksize) + 1, commastring);
  2016.         } else // exactly on a block boundary
  2017.         {   comma(bytes / size.blocksize, commastring);
  2018. }   }   }
  2019.  
  2020. MODULE void __inline progressbar(ULONG level)
  2021. {   if (!(level % increment))
  2022.     {   SetGadgetAttrs
  2023.         (   size_gadgets[GID_8_FG1], MainWindowPtr, NULL,
  2024.             FUELGAUGE_Level, level,
  2025.             TAG_END
  2026.         );
  2027. }   }
  2028.  
  2029.